<template>
  <div id="app" >
    <a-spin :spinning="loading" :tip="tip">
    <a-tabs :default-active-key="activeKey" v-model="activeKey"  @change="tabChange">
      <!-- <a-tab-pane key="upload" tab="录制">
        <div class="no-file-panel">

          <div @click="openDir">
            <p class="ant-upload-drag-icon">
              <a-icon type="upload" />
            </p>
            
          </div>
          <div @click="openDir">
            <p class="ant-upload-drag-icon">
              <a-icon type="video-camera" />
            </p>
          </div>
        </div>
      </a-tab-pane> -->

      <a-tab-pane key="file"  tab="文件">
        <div>
          <div style="display: flex; gap: 32px;margin:0 20px 20px 20px;  ">
            <a-form-model layout="inline" :model="form" >
              <template v-if = "hasFile">
                <a-form-model-item label="文件名">
                  <a-input v-model="form.fileName" placeholder="录制文件的名称">
                    <a-icon slot="prefix" type="user" style="color:rgba(0,0,0,.25)" />
                  </a-input>
                </a-form-model-item>
                <a-form-model-item label="图片文件夹">
                  <a-input v-model="form.dirName" placeholder="Password">
                    <a-icon slot="prefix" type="lock" style="color:rgba(0,0,0,.25)" />
                  </a-input>
                </a-form-model-item>
                <a-form-model-item >
                  <a-button type="primary" @click="doSave"> 保存 </a-button>
                </a-form-model-item>
              </template>
              
              <a-form-model-item>
                <a-button type="primary"  @click="openDir"> <a-icon type="upload" /> </a-button>
              </a-form-model-item>
            </a-form-model>
          </div>
          <a-tabs default-active-key="file" tabPosition="right" size="small" type="card" :tabBarStyle="tabBarStyle"  v-model="activeView" v-if="hasFile">
            <a-tab-pane key="file"  tab="文本" >
              <!-- <CodeEdit v-model="content" style="height: calc(100vh - 120px);" /> -->
              <ace-editor style="height: calc(100vh - 140px); background-color: black;"  theme="tomorrow_night_eighties" :value="content" lang="json"></ace-editor>
            </a-tab-pane>
            <a-tab-pane key="view" tab="预览">
              
              <div class="card-list" style="background-color: #ececec; padding: 20px;">
                <template v-if="record.actions">
                  <action-card :key="item.t" v-for="(item) in record.actions" 
                    v-bind="item" :btn="item.key" 
                    :imgurl="getActionImg(item)" 
                    v-model="item.remark"
                    @imgclick="showModal(item)" 
>
                  </action-card>
                </template>
              </div>
            </a-tab-pane>
          </a-tabs>
        </div>        
         
        
          
      </a-tab-pane>

      <a-tab-pane key="code" tab="代码">
        <a-form-model layout="inline"  >
          <a-form-model-item label="选择模板" >
            <a-select v-model="currTpl"  style="width: 300px;">
              <a-select-opt-group>
                <span slot="label"><a-icon type="deployment-unit" />内置模板</span>
                <a-select-option v-for="(content,file) in templates" :key="file" :value="file">{{file}}</a-select-option>
              </a-select-opt-group>
              <a-select-opt-group>
                <span slot="label"><a-icon type="user" />自定义模板</span>
                <a-select-option v-for="(content,file) in customTemplates" :key="file" :value="file">{{file}}</a-select-option>
              </a-select-opt-group>
              </a-select>
          </a-form-model-item> 

          <a-form-model-item label="模板名称" v-if="showAddTplInput">
            <a-input v-model="newTplName" placeholder="请输入模板名称" />
          </a-form-model-item>

          <a-form-model-item v-if="!showAddTplInput">
            <a-button type="primary"   @click="showAddTplInput = !showAddTplInput"><a-icon type="plus" />新建模板</a-button>
          </a-form-model-item>
          <a-form-model-item  v-if="showAddTplInput">
            <a-button type="primary" @click="addNewTpl"><a-icon type="check" /></a-button>
          </a-form-model-item>
          <a-form-model-item v-if="isCustomTpl(currTpl)">
            <a-button type="danger" @click="delTpl" ><a-icon type="delete"/>删除模板</a-button>
          </a-form-model-item>
          <a-form-model-item>
            <a-upload :beforeUpload="beforeTplUpload">
              <a-button type="primary"> <a-icon type="upload" /> 上传配置 </a-button>
            </a-upload>
          </a-form-model-item>
          <a-form-model-item>
            <a-button type="primary" @click="doExport" ><a-icon type="export" />导出配置</a-button>
          </a-form-model-item>
        </a-form-model>
        
        <div class="code-panel-root">
          <ace-editor style="height: calc(100vh - 120px); width: 50%;"  theme="tomorrow_night_eighties" :value=currTplContent() lang="python" :read-only="!isCustomTpl(currTpl)" @input="onTplInput"> 
          </ace-editor>
          <ace-editor ref="tplResEditor" style="height: calc(100vh - 120px); width: 50%;"  theme="tomorrow_night_eighties" lang="python" :read-only="true">
          </ace-editor>
        </div>
       
      </a-tab-pane>
    </a-tabs>

    <a-modal v-model="modal.visible" :title="modal.title" @ok="handleOk">
      <div class="modal-content">
        <vue-cropper style="width: 300px; height:260px;"
          ref="cropper"
          :img="getActionImg(modal.act)"
          :autoCropArea="1"
          :outputSize="1"
          :outputType="'png'"
          :info="true"
          :full="true"
          :canMove="true"
          :centerBox="true"
          :canMoveBox="true"
          :original="false"
          :autoCrop="true"
        ></vue-cropper>
        <a-form-model :model="form" :label-col="labelCol" :wrapper-col="wrapperCol">
          <a-form-model-item label="名称">
            <a-input v-model="form.name" />
          </a-form-model-item>
          <a-form-model-item label="阈值">
            <a-input v-model="form.threshold" />
          </a-form-model-item>
        </a-form-model>
      </div>
    </a-modal>
  </a-spin>
  </div>
</template>

<script>
import CodeEdit from './components/CodeEdit.vue'
import ActionCard from './components/ActionCard.vue'
import AceEditor from './components/AceEditor.vue'
import templates from './utils/importTpls'
import themes from '@/utils/importTheme.js'
import Vue from 'vue'

// import { Row,Col } from 'ant-design-vue';
export default {
  name: 'App',
  components: {
    CodeEdit,
    ActionCard,
    AceEditor
  },
  data() {
    return {
      fileHandle:null,
      dirHandle:null,
      imgDirHandle:null,

      activeKey: 'file',
      activeView:'view',
      
      loading:false,
      tip:"操作中,请稍等 ...",

      content: '',
      layout:{
        lineCount:4,
        span:6,
      },
      tabBarStyle:{
        textAlign:'left'
      },
      record:{},
      imgMap:{},
      modal:{
        visible:false,
        title:'图片查看/裁剪',
        act:{},
      },
      labelCol: { span: 4 },
      wrapperCol: { span: 14 },
      form: {
        name: '',
        threshold: 0.8,
        fileName:'',
        dirName:'',
      },

      templates:templates,
      themes:themes,
      currTpl:null,
      newTplName:'',
      showAddTplInput:false,
      tplStorageKey:"customTpl",
      customTemplates:{},
    }
  },
  computed:{
    hasFile(){
      return this.fileHandle
    },
   
  },
  watch:{
    currTpl(){
      this.setTplRenderResult(this.renderTpl())
    }
  },
  mounted() {
    console.log("mounted")
    this.currTpl = Object.keys(this.templates)[0]
    let customTpl = localStorage.getItem(this.tplStorageKey)
    if(!customTpl){
      localStorage.setItem(this.tplStorageKey,"{}")
    }
    customTpl = localStorage.getItem(this.tplStorageKey)
    try{
      customTpl = JSON.parse(customTpl)
      console.log("custom", customTpl)
      Object.keys(customTpl).forEach(key=>{
      if(!this.customTemplates[key]){
        Vue.set(this.customTemplates,key,customTpl[key])
      }
    })
    }catch(e){
      localStorage.setItem(this.tplStorageKey,"{}")
    }
   
    
  },
  methods: {
    async findEntry(root,name,type){
      for await (const entry of root.values()) {
        if(type && entry.kind !== type)
          continue
        if (name instanceof RegExp){
          if (name.test(entry.name)){
            console.log(entry)
            return entry
          }
        }else{
          if (entry.name === name){
            console.log(entry)
            return entry
          }
        }
      }
      return null
    },

    currTplContent(){
      if (!this.currTpl) return ''
      if (this.currTpl in this.templates){
        return this.templates[this.currTpl]
      }
      if(this.currTpl in this.customTemplates){
        return this.customTemplates[this.currTpl]
      }
      return ''
    },

    tabChange(activeKey){
      if (activeKey === 'code') {
       this.$nextTick(()=>{
        this.setTplRenderResult(this.renderTpl())
       })
      }
    },

    async openDir(){
      this.loading = true
      this.dirHandle = await window.showDirectoryPicker();
      this.fileHandle = await this.findEntry(this.dirHandle,/\.ajs$/,'file')
      if (!this.fileHandle) {
        this.loading = false
        this.$message.error('未找到文件,请选择包含.ajs文件的目录')
        return
      }else{
        this.form.fileName = this.fileHandle.name
      }
      const file = await this.fileHandle.getFile();
      const content = await file.text();
      this.content = content
      
      let record = JSON.parse(content)
      await this.loadImgs(record)
      this.$nextTick(()=>{
        this.activeKey = 'file'
        this.record = record
        this.loading = false
      })
    },
    async loadImgs(record){
      this.loading = true
      let imgDir = record.imgdir
      this.form.dirName = imgDir
      this.imgDirHandle = await this.findEntry(this.dirHandle,imgDir,'directory')
      
      for await (const entry of this.imgDirHandle.values()) {
        if (entry.kind === 'file') {
            const file = await entry.getFile();
            const objectURL = URL.createObjectURL(file);
            Vue.set(this.imgMap,entry.name.slice(0,-4),objectURL)
        }
      }
      this.loading = false
    },

    getActionImg(act){
      if (act.ext_data && act.ext_data.img)
        return this.imgMap[act.ext_data.img.slice(0,-4)]
      return ''
    },

    async doSave(){
      this.loading = true
      // 重命名目录
      if(this.imgDirHandle.name != this.form.dirName ){
        let newDir = await this.dirHandle.getDirectoryHandle(this.form.dirName, { create: true })
        for await (const entry of this.imgDirHandle.values()) {
          if (entry.kind === 'file') {
            await entry.move(newDir,entry.name)
          }
        }
        await this.dirHandle.removeEntry(this.imgDirHandle.name)
        this.record.imgdir = this.form.dirName
        this.imgDirHandle = newDir
      }
      // 重命名图片文件
      if(this.fileHandle.name != this.form.fileName ){
        await this.fileHandle.move(this.form.fileName)
      }
      // 保存写入图片文件
      this.content = JSON.stringify(this.record, null, 2)
      try {
          const writable = await this.fileHandle.createWritable();
          await writable.write(this.content);
          await writable.close();
          this.loading = false
      } catch (err) {
          console.error(err.name, err.message);
          this.loading = false
      }
    },
    async handleOk(){
      this.$refs.cropper.getCropBlob(async data  => {
        // 修改显示图片
        let  url = URL.createObjectURL(data)
        // console.log("imgUrl",url)
        let act = this.modal.act
        let imgHandle = await this.findEntry(this.imgDirHandle,act.ext_data.img,'file')

         // 文件重命名
         if(this.form.name != act.ext_data.img.slice(0,-4)){
            await imgHandle.move(this.form.name +'.png')
            delete this.imgMap[act.ext_data.img.slice(0,-4)]
            this.imgMap[this.form.name] = url
            act.ext_data.img = this.form.name +'.png'
            await this.doSave()
          }else{
            this.imgMap[act.ext_data.img.slice(0,-4)] = url
          }
            // 2. 创建可写流
          const writable = await imgHandle.createWritable();
          // 3. 写入数据
          await writable.write(data);
          // 4. 关闭流
          await writable.close();

        this.modal.visible = false
      })
      
    },
    showModal(act){
      this.modal.act = act
      this.modal.visible = true
      this.form.threshold = act.ext_data.threshold ? act.ext_data.threshold : 0.8
      this.form.name = act.ext_data.img.slice(0,-4) 
    },

    isCustomTpl(key){
      let customTpl = localStorage.getItem(this.tplStorageKey)
      if(customTpl){
        customTpl = JSON.parse(customTpl)
        return key in customTpl
      }else{
        return false
      }
    },
    renderTpl(){
      if(this.currTpl){
        let tpl = this.currTplContent()
        const result = ejs.render(tpl, this.record);
        return result
      }
    },
    onTplInput(content){
      if (!this.isCustomTpl(this.currTpl)) return
      this.customTemplates[this.currTpl] = content
      let customTpl = localStorage.getItem(this.tplStorageKey)
      if(customTpl){
        customTpl = JSON.parse(customTpl)
        customTpl[this.currTpl] = content
        localStorage.setItem(this.tplStorageKey,JSON.stringify(customTpl))
      }else{
        customTpl = {}
        customTpl[this.currTpl] = content
        localStorage.setItem(this.tplStorageKey,JSON.stringify(customTpl))
      }

      this.setTplRenderResult(this.renderTpl())
    },
    setTplRenderResult(content){
      let editor = this.$refs.tplResEditor
      if (editor)
        editor.setValue(content)
    },
    addNewTpl(){
      if(!this.newTplName){
        this.$message.error("请输入模板名称")
      }
      if(this.newTplName in this.templates || this.newTplName in this.customTemplates){
        this.$message.error("模板名称已存在")
      }else{
        this.customTemplates[this.newTplName] = ""
        let customTpl = localStorage.getItem(this.tplStorageKey)
        if(customTpl){
          customTpl = JSON.parse(customTpl)
          customTpl[this.newTplName] = ""
        }else{
          customTpl = {}
          customTpl[this.newTplName] = ""
        }
        localStorage.setItem(this.tplStorageKey,JSON.stringify(customTpl))
        this.currTpl = this.newTplName
        this.newTplName = ""
        this.showAddTplInput = false
      }
    },
    delTpl(){
      if(this.currTpl){
        let customTpl = localStorage.getItem(this.tplStorageKey)
        customTpl = JSON.parse(customTpl)
        delete customTpl[this.currTpl]
        localStorage.setItem(this.tplStorageKey,JSON.stringify(customTpl))
        delete this.customTemplates[this.currTpl]
        for (const k in this.templates){
          this.currTpl = k
          this.newTplName = ""
          return
        }
        
      }
    },

    downloadFile(fileName, content) {
      // 创建一个 Blob 对象
      const blob = new Blob([content], { type: 'text/plain' });
      // 创建一个 URL 对象
      const url = URL.createObjectURL(blob);
      // 创建一个 <a> 元素
      const a = document.createElement('a');
      a.href = url;
      a.download = fileName;
      // 将 <a> 元素添加到文档中
      document.body.appendChild(a);
      // 触发点击事件
      a.click();
      // 移除 <a> 元素
      document.body.removeChild(a);
      // 释放 URL 对象
      URL.revokeObjectURL(url);
    },

    doExport(){
      let customTpl = localStorage.getItem(this.tplStorageKey)
      if(!customTpl) return
      this.downloadFile('customTpl.json', customTpl)
    },
    doImport(){

    },
    beforeTplUpload(file){
      console.log(file)
      const reader = new FileReader();

      // 此处需要使用 箭头函数 保证 this 指向当前组件
      reader.onload = (e) => {
        let result = e.target.result
        try {
          let fileCfg = JSON.parse(result)
          let oldCfg = localStorage.getItem(this.tplStorageKey)
          oldCfg = JSON.parse(oldCfg)
          let mergeRes = Object.assign({},oldCfg,fileCfg)
          localStorage.setItem(this.tplStorageKey,JSON.stringify(mergeRes))
          this.customTemplates = mergeRes
        } catch (error) {
          console.log(error)
        }
      }
      reader.readAsText(file);
      return false
    }
  },
}
</script>

<style>
#app {
  font-family: Avenir, Helvetica, Arial, sans-serif;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  text-align: center;
  color: #2c3e50;
  height: 100%;
  overflow: hidden;
}
.ant-upload-list{
  display: none;
}
.no-file-panel{
  display: flex;
  justify-content: center;
  align-items: center;
  flex-direction: row;
  gap: 20px;
  height: 100%;
}

.record-icon,.ant-upload-drag-icon{
  font-size:120px;
  line-height: 1.5;
}
.card-list{
  display: flex;
  flex-wrap: wrap;
  gap: 20px 1% ;
  max-height: calc(100vh - 100px);
  justify-content: space-between; /* 调整子元素之间的间距 */
  align-items:stretch;    /* 垂直居中对齐子元素 */
  overflow: auto;
}
.action-card{
  min-width: 24%;
  flex:1;
  margin-top: 20px;
}
.modal-content{
  display: flex;
  flex-direction: row;
  flex: 0 0 48%;
  justify-content: stretch;
  justify-items: stretch;
  gap: 20px;
}

.code-panel-root{
  display: flex;
  flex-direction: row;
}
</style>
